﻿#include <algorithm>
#include <gtest/gtest.h>
#include <iostream>
#include <vector>

#include <learn/alg/alg_geom.h>
#include <learn/geom/vec.h>
#include <learn/utils/adaptor_eigen.h>
#include <learn/utils/adaptor_occ.h>
#include <learn/utils/output.h>

using namespace xi;
using namespace xi::geom;
using namespace xi::alg;
using namespace xi::utils;

TEST(TestAdaptorOCC, Vec)
{
    {
        Vec3 v(1.0, 2.0, 3.0);
        auto adaptor = Adaptor_OCCVec<3>(v);
        gp_Pnt p1 = adaptor;
        gp_Vec v1 = adaptor;
        Vec3 v2 = adaptor;

        EXPECT_EQ(p1.X(), v.x());
        EXPECT_EQ(p1.Y(), v.y());
        EXPECT_EQ(p1.Z(), v.z());

        EXPECT_EQ(v1.X(), v.x());
        EXPECT_EQ(v1.Y(), v.y());
        EXPECT_EQ(v1.Z(), v.z());

        EXPECT_EQ(v2.x(), v.x());
        EXPECT_EQ(v2.y(), v.y());
        EXPECT_EQ(v2.z(), v.z());
    }

    {
        gp_Pnt v(1.0, 2.0, 3.0);
        auto adaptor = Adaptor_OCCVec<3>(v);

        gp_Pnt p1 = adaptor;
        gp_Vec v1 = adaptor;
        Vec3 v2 = adaptor;

        EXPECT_EQ(p1.X(), v.X());
        EXPECT_EQ(p1.Y(), v.Y());
        EXPECT_EQ(p1.Z(), v.Z());

        EXPECT_EQ(v1.X(), v.X());
        EXPECT_EQ(v1.Y(), v.Y());
        EXPECT_EQ(v1.Z(), v.Z());

        EXPECT_EQ(v2.x(), v.X());
        EXPECT_EQ(v2.y(), v.Y());
        EXPECT_EQ(v2.z(), v.Z());
    }

    {
        gp_Vec v(1.0, 2.0, 3.0);
        auto adaptor = Adaptor_OCCVec<3>(v);

        gp_Pnt p1 = adaptor;
        gp_Vec v1 = adaptor;
        Vec3 v2 = adaptor;

        EXPECT_EQ(p1.X(), v.X());
        EXPECT_EQ(p1.Y(), v.Y());
        EXPECT_EQ(p1.Z(), v.Z());

        EXPECT_EQ(v1.X(), v.X());
        EXPECT_EQ(v1.Y(), v.Y());
        EXPECT_EQ(v1.Z(), v.Z());

        EXPECT_EQ(v2.x(), v.X());
        EXPECT_EQ(v2.y(), v.Y());
        EXPECT_EQ(v2.z(), v.Z());
    }

    {
        Vec2 v(1.0, 2.0);
        auto adaptor = Adaptor_OCCVec<2>(v);

        gp_Pnt2d p1 = adaptor;
        gp_Vec2d v1 = adaptor;
        Vec2 v2 = adaptor;

        EXPECT_EQ(p1.X(), v.x());
        EXPECT_EQ(p1.Y(), v.y());

        EXPECT_EQ(v1.X(), v.x());
        EXPECT_EQ(v1.Y(), v.y());

        EXPECT_EQ(v2.x(), v.x());
        EXPECT_EQ(v2.y(), v.y());
    }

    {
        gp_Pnt2d v(1.0, 2.0);
        auto adaptor = Adaptor_OCCVec<2>(v);

        gp_Pnt2d p1 = adaptor;
        gp_Vec2d v1 = adaptor;
        Vec2 v2 = adaptor;

        EXPECT_EQ(p1.X(), v.X());
        EXPECT_EQ(p1.Y(), v.Y());

        EXPECT_EQ(v1.X(), v.X());
        EXPECT_EQ(v1.Y(), v.Y());

        EXPECT_EQ(v2.x(), v.X());
        EXPECT_EQ(v2.y(), v.Y());
    }

    {
        gp_Vec2d v(1.0, 2.0);
        auto adaptor = Adaptor_OCCVec<2>(v);

        gp_Pnt2d p1 = adaptor;
        gp_Vec2d v1 = adaptor;
        Vec2 v2 = adaptor;

        EXPECT_EQ(p1.X(), v.X());
        EXPECT_EQ(p1.Y(), v.Y());

        EXPECT_EQ(v1.X(), v.X());
        EXPECT_EQ(v1.Y(), v.Y());

        EXPECT_EQ(v2.x(), v.X());
        EXPECT_EQ(v2.y(), v.Y());
    }
}

TEST(TestAdaptorOCC, vector)
{
    {
        std::vector<Vec3> vec;
        vec.emplace_back(1.0, 2.0, 3.0);
        vec.emplace_back(4.0, 5.0, 6.0);
        vec.emplace_back(7.0, 8.0, 9.0);

        auto adaptor = Adaptor_OCC1(vec);
        TColgp_Array1OfPnt pnts = adaptor;
        std::vector<Vec3> vec3s = adaptor;

        EXPECT_EQ(pnts.Size(), 3);
        EXPECT_EQ(vec3s.size(), 3);

        for (int i = 0; i < 3; i++)
        {
            EXPECT_EQ(pnts.Value(i + 1).X(), vec[i].x());
            EXPECT_EQ(pnts.Value(i + 1).Y(), vec[i].y());
            EXPECT_EQ(pnts.Value(i + 1).Z(), vec[i].z());

            EXPECT_EQ(vec3s[i].x(), vec[i].x());
            EXPECT_EQ(vec3s[i].y(), vec[i].y());
            EXPECT_EQ(vec3s[i].z(), vec[i].z());
        }
    }

    {
        std::vector<Vec2> vec;
        vec.emplace_back(1.0, 2.0);
        vec.emplace_back(4.0, 5.0);
        vec.emplace_back(7.0, 8.0);

        auto adaptor = Adaptor_OCC1(vec);
        TColgp_Array1OfPnt2d pnts = adaptor;
        std::vector<Vec2> vec2s = adaptor;

        EXPECT_EQ(pnts.Size(), 3);
        EXPECT_EQ(vec2s.size(), 3);

        for (int i = 0; i < 3; i++)
        {
            EXPECT_EQ(pnts.Value(i + 1).X(), vec[i].x());
            EXPECT_EQ(pnts.Value(i + 1).Y(), vec[i].y());

            EXPECT_EQ(vec2s[i].x(), vec[i].x());
            EXPECT_EQ(vec2s[i].y(), vec[i].y());
        }
    }

    {
        std::vector<int> vec;
        vec.emplace_back(1);
        vec.emplace_back(2);
        vec.emplace_back(3);

        auto adaptor = Adaptor_OCC1(vec);
        TColStd_Array1OfInteger ints = adaptor;
        std::vector<int> vecInts = adaptor;

        EXPECT_EQ(ints.Size(), 3);
        EXPECT_EQ(vecInts.size(), 3);

        for (int i = 0; i < 3; i++)
        {
            EXPECT_EQ(ints.Value(i + 1), vec[i]);
            EXPECT_EQ(vecInts[i], vec[i]);
        }
    }

    {
        std::vector<double> vec;
        vec.emplace_back(1.0);
        vec.emplace_back(2.0);
        vec.emplace_back(3.0);

        auto adaptor = Adaptor_OCC1(vec);
        TColStd_Array1OfReal reals = adaptor;
        std::vector<double> vecReals = adaptor;

        EXPECT_EQ(reals.Size(), 3);
        EXPECT_EQ(vecReals.size(), 3);

        for (int i = 0; i < 3; i++)
        {
            EXPECT_EQ(reals.Value(i + 1), vec[i]);
            EXPECT_EQ(vecReals[i], vec[i]);
        }
    }
}

TEST(TestAdaptorOCC, tcol)
{
    {
        TColgp_Array1OfPnt vec(1, 3);
        vec.SetValue(1, gp_Pnt(1.0, 2.0, 3.0));
        vec.SetValue(2, gp_Pnt(4.0, 5.0, 6.0));
        vec.SetValue(3, gp_Pnt(7.0, 8.0, 9.0));

        auto adaptor = Adaptor_OCC1<Vec3>(vec);
        TColgp_Array1OfPnt pnts = adaptor;
        std::vector<Vec3> vec3s = adaptor;

        EXPECT_EQ(pnts.Size(), 3);
        EXPECT_EQ(vec3s.size(), 3);

        for (int i = 0; i < 3; i++)
        {
            EXPECT_EQ(pnts.Value(i + 1).X(), vec[i + 1].X());
            EXPECT_EQ(pnts.Value(i + 1).Y(), vec[i + 1].Y());
            EXPECT_EQ(pnts.Value(i + 1).Z(), vec[i + 1].Z());

            EXPECT_EQ(vec3s[i].x(), vec[i + 1].X());
            EXPECT_EQ(vec3s[i].y(), vec[i + 1].Y());
            EXPECT_EQ(vec3s[i].z(), vec[i + 1].Z());
        }
    }

    {
        TColgp_Array1OfPnt2d vec(1, 3);
        vec.SetValue(1, gp_Pnt2d(1.0, 2.0));
        vec.SetValue(2, gp_Pnt2d(4.0, 5.0));
        vec.SetValue(3, gp_Pnt2d(7.0, 8.0));

        auto adaptor = Adaptor_OCC1<Vec2>(vec);
        TColgp_Array1OfPnt2d pnts = adaptor;
        std::vector<Vec2> vec2s = adaptor;

        EXPECT_EQ(pnts.Size(), 3);
        EXPECT_EQ(vec2s.size(), 3);

        for (int i = 0; i < 3; i++)
        {
            EXPECT_EQ(pnts.Value(i + 1).X(), vec[i + 1].X());
            EXPECT_EQ(pnts.Value(i + 1).Y(), vec[i + 1].Y());

            EXPECT_EQ(vec2s[i].x(), vec[i + 1].X());
            EXPECT_EQ(vec2s[i].y(), vec[i + 1].Y());
        }
    }

    {
        TColStd_Array1OfInteger vec(1, 3);
        vec.SetValue(1, 1);
        vec.SetValue(2, 2);
        vec.SetValue(3, 3);

        auto adaptor = Adaptor_OCC1<int>(vec);
        TColStd_Array1OfInteger ints = adaptor;
        std::vector<int> vecInts = adaptor;

        EXPECT_EQ(ints.Size(), 3);
        EXPECT_EQ(vecInts.size(), 3);

        for (int i = 0; i < 3; i++)
        {
            EXPECT_EQ(ints.Value(i + 1), vec[i + 1]);
            EXPECT_EQ(vecInts[i], vec[i + 1]);
        }
    }

    {
        TColStd_Array1OfReal vec(1, 3);
        vec.SetValue(1, 1.0);
        vec.SetValue(2, 2.0);
        vec.SetValue(3, 3.0);

        auto adaptor = Adaptor_OCC1<double>(vec);
        TColStd_Array1OfReal reals = adaptor;
        std::vector<double> vecReals = adaptor;

        EXPECT_EQ(reals.Size(), 3);
        EXPECT_EQ(vecReals.size(), 3);

        for (int i = 0; i < 3; i++)
        {
            EXPECT_EQ(reals.Value(i + 1), vec[i + 1]);
            EXPECT_EQ(vecReals[i], vec[i + 1]);
        }
    }
}

TEST(TestAdaptorOCC, knot)
{
    {
        auto u = Alg_Knot<3>::equally(10, 3);
        auto adaptor = Adaptor_OCCKnot(u);

        auto [Knots, Mults] = adaptor.occ();
        std::vector<double> knots = adaptor;

        // std::cout << "Knots: " << std::endl;
        // for (auto knot : Knots)
        // {
        //     std::cout << knot << " ";
        // }
        // std::cout << std::endl;

        // std::cout << "Mults: " << std::endl;
        // for (auto mult : Mults)
        // {
        //     std::cout << mult << " ";
        // }
        // std::cout << std::endl;

        // std::cout << knots << std::endl;
    }

    {
        TColStd_Array1OfReal u(1, 10);
        TColStd_Array1OfInteger v(1, 10);
        for (int i = 1; i <= 10; i++)
        {
            u.SetValue(i, i);
            v.SetValue(i, 2);
        }

        auto adaptor = Adaptor_OCCKnot(u, v);

        auto [Knots, Mults] = adaptor.occ();
        std::vector<double> knots = adaptor;

        // std::cout << "Knots: " << std::endl;
        // for (auto knot : Knots)
        // {
        //     std::cout << knot << " ";
        // }
        // std::cout << std::endl;

        // std::cout << "Mults: " << std::endl;
        // for (auto mult : Mults)
        // {
        //     std::cout << mult << " ";
        // }
        // std::cout << std::endl;

        // std::cout << knots << std::endl;
    }
}

TEST(TestAdaptorOCC, BSpline)
{
    // geom 转 occ
    {
        std::vector<Vec3> vec;
        vec.emplace_back(1.0, 2.0, 3.0);
        vec.emplace_back(4.0, 5.0, 6.0);
        vec.emplace_back(7.0, 8.0, 9.0);
        vec.emplace_back(10.0, 11.0, 12.0);

        std::vector<double> knots{0, 0, 0, 0, 1, 1, 1, 1};

        auto curve = std::make_shared<geom::Geom_BSplineCurve<3>>(std::move(vec), std::move(knots), 3);
        auto adaptor = Adaptor_OCCBSplineCurve<3>(curve.get());

        std::shared_ptr<geom::Geom_BSplineCurve<3>> cur = adaptor;
        Handle(::Geom_BSplineCurve) occCurve = adaptor;

        for (int i = 0; i < 10; i++)
        {
            geom::Vec3 p1 = Adaptor_OCCVec<3>(occCurve->Value(i * 0.1));
            auto p2 = cur->value(i * 0.1);
            EXPECT_LE((p1 - p2).modulus(), 1e-10);
        }
    }

    // occ 转 geom
    {
        std::vector<Vec3> vec;
        vec.emplace_back(1.0, 2.0, 3.0);
        vec.emplace_back(4.0, 5.0, 6.0);
        vec.emplace_back(7.0, 8.0, 9.0);
        vec.emplace_back(10.0, 11.0, 12.0);

        std::vector<double> knots{0, 0, 0, 0, 1, 1, 1, 1};

        auto kA = Adaptor_OCCKnot(knots);
        auto [Knots, Mults] = kA.occ();

        Handle(::Geom_BSplineCurve) curve = new ::Geom_BSplineCurve(Adaptor_OCC1(vec), Knots, Mults, 3);
        auto adaptor = Adaptor_OCCBSplineCurve<3>(curve);

        std::shared_ptr<geom::Geom_BSplineCurve<3>> cur = adaptor;
        Handle(::Geom_BSplineCurve) occCurve = adaptor;

        for (int i = 0; i < 10; i++)
        {
            geom::Vec3 p1 = Adaptor_OCCVec<3>(occCurve->Value(i * 0.1));
            auto p2 = cur->value(i * 0.1);
            EXPECT_LE((p1 - p2).modulus(), 1e-10);
        }
    }

    // geom 加权转 occ
    {
        std::vector<Vec4> vec;
        vec.emplace_back(1.0, 2.0, 3.0, 1.0);
        vec.emplace_back(4.0, 5.0, 6.0, 2.0);
        vec.emplace_back(7.0, 8.0, 9.0, 3.0);
        vec.emplace_back(10.0, 11.0, 12.0, 4.0);

        std::vector<double> knots{0, 0, 0, 0, 1, 1, 1, 1};

        auto curve = std::make_shared<geom::Geom_BSplineCurve<3, true>>(std::move(vec), std::move(knots), 3);
        auto adaptor = Adaptor_OCCBSplineCurve<3, true>(curve.get());

        std::shared_ptr<geom::Geom_BSplineCurve<3, true>> cur = adaptor;
        Handle(::Geom_BSplineCurve) occCurve = adaptor;

        for (int i = 0; i < 10; i++)
        {
            geom::Vec3 p1 = Adaptor_OCCVec<3>(occCurve->Value(i * 0.1));
            auto p2 = cur->value(i * 0.1);
            EXPECT_LE((p1 - p2).modulus(), 1e-10);
        }
    }

    // occ 加权转 geom
    {
        std::vector<Vec3> vec;
        vec.emplace_back(1.0, 2.0, 3.0);
        vec.emplace_back(4.0, 5.0, 6.0);
        vec.emplace_back(7.0, 8.0, 9.0);
        vec.emplace_back(10.0, 11.0, 12.0);

        std::vector<double> knots{0, 0, 0, 0, 1, 1, 1, 1};
        std::vector<double> weights{1, 2, 3, 4};

        auto kA = Adaptor_OCCKnot(knots);
        auto [Knots, Mults] = kA.occ();
        auto wA = Adaptor_OCC1(weights);

        Handle(::Geom_BSplineCurve) curve = new ::Geom_BSplineCurve(Adaptor_OCC1(vec), wA, Knots, Mults, 3);
        auto adaptor = Adaptor_OCCBSplineCurve<3>(curve);

        std::shared_ptr<geom::Geom_BSplineCurve<3>> cur = adaptor;
        Handle(::Geom_BSplineCurve) occCurve = adaptor;

        for (int i = 0; i < 10; i++)
        {
            geom::Vec3 p1 = Adaptor_OCCVec<3>(occCurve->Value(i * 0.1));
            auto p2 = cur->value(i * 0.1);
            EXPECT_LE((p1 - p2).modulus(), 1e-10);
        }
    }

    // geom 曲面转 occ
    {
        std::vector<Vec3> vec;
        vec.emplace_back(1.0, 2.0, 3.0);
        vec.emplace_back(4.0, 5.0, 6.0);
        vec.emplace_back(7.0, 8.0, 9.0);

        vec.emplace_back(13.0, 14.0, 15.0);
        vec.emplace_back(16.0, 17.0, 18.0);
        vec.emplace_back(19.0, 20.0, 21.0);

        vec.emplace_back(25.0, 26.0, 27.0);
        vec.emplace_back(28.0, 29.0, 30.0);
        vec.emplace_back(31.0, 32.0, 33.0);

        vec.emplace_back(37.0, 38.0, 39.0);
        vec.emplace_back(40.0, 41.0, 42.0);
        vec.emplace_back(43.0, 44.0, 45.0);

        std::vector<double> knotsU{0, 0, 0, 0, 1, 1, 1, 1};
        std::vector<double> knotsV{0, 0, 0, 1, 1, 1};

        auto surface =
            std::make_shared<geom::Geom_BSplineSurface<3>>(std::move(vec), std::move(knotsU), std::move(knotsV), 3, 2);
        auto adaptor = Adaptor_OCCBSplineSurface<3>(surface.get());

        std::shared_ptr<geom::Geom_BSplineSurface<3>> sur = adaptor;
        Handle(::Geom_BSplineSurface) occSurface = adaptor;

        for (int i = 0; i < 10; i++)
        {
            for (int j = 0; j < 10; j++)
            {
                geom::Vec3 p1 = Adaptor_OCCVec<3>(occSurface->Value(i * 0.1, j * 0.1));
                auto p2 = sur->value(i * 0.1, j * 0.1);
                EXPECT_LE((p1 - p2).modulus(), 1e-10);
            }
        }
    }

    // ooc 曲面转 geom
    {
        TColgp_Array2OfPnt vec(1, 4, 1, 3);
        vec.SetValue(1, 1, gp_Pnt(1.0, 2.0, 3.0));
        vec.SetValue(1, 2, gp_Pnt(4.0, 5.0, 6.0));
        vec.SetValue(1, 3, gp_Pnt(7.0, 8.0, 9.0));

        vec.SetValue(2, 1, gp_Pnt(13.0, 14.0, 15.0));
        vec.SetValue(2, 2, gp_Pnt(16.0, 17.0, 18.0));
        vec.SetValue(2, 3, gp_Pnt(19.0, 20.0, 21.0));

        vec.SetValue(3, 1, gp_Pnt(25.0, 26.0, 27.0));
        vec.SetValue(3, 2, gp_Pnt(28.0, 29.0, 30.0));
        vec.SetValue(3, 3, gp_Pnt(31.0, 32.0, 33.0));

        vec.SetValue(4, 1, gp_Pnt(37.0, 38.0, 39.0));
        vec.SetValue(4, 2, gp_Pnt(40.0, 41.0, 42.0));
        vec.SetValue(4, 3, gp_Pnt(43.0, 44.0, 45.0));

        std::vector<double> knotsU{0, 0, 0, 0, 1, 1, 1, 1};
        std::vector<double> knotsV{0, 0, 0, 1, 1, 1};

        auto kA = Adaptor_OCCKnot(knotsU);
        auto [KnotsU, MultsU] = kA.occ();
        auto kB = Adaptor_OCCKnot(knotsV);
        auto [KnotsV, MultsV] = kB.occ();

        Handle(::Geom_BSplineSurface) surface = new ::Geom_BSplineSurface(vec, KnotsU, KnotsV, MultsU, MultsV, 3, 2);
        auto adaptor = Adaptor_OCCBSplineSurface<3>(surface);

        std::shared_ptr<geom::Geom_BSplineSurface<3>> sur = adaptor;
        Handle(::Geom_BSplineSurface) occSurface = adaptor;

        for (int i = 0; i < 10; i++)
        {
            for (int j = 0; j < 10; j++)
            {
                geom::Vec3 p1 = Adaptor_OCCVec<3>(occSurface->Value(i * 0.1, j * 0.1));
                auto p2 = sur->value(i * 0.1, j * 0.1);
                EXPECT_LE((p1 - p2).modulus(), 1e-10);
            }
        }
    }

    // geom 加权曲面转 occ
    {
        std::vector<Vec4> vec;
        vec.emplace_back(1.0, 2.0, 3.0, 1.0);
        vec.emplace_back(4.0, 5.0, 6.0, 2.0);
        vec.emplace_back(7.0, 8.0, 9.0, 3.0);

        vec.emplace_back(13.0, 14.0, 15.0, 1.0);
        vec.emplace_back(16.0, 17.0, 18.0, 2.0);
        vec.emplace_back(19.0, 20.0, 21.0, 3.0);

        vec.emplace_back(25.0, 26.0, 27.0, 1.0);
        vec.emplace_back(28.0, 29.0, 30.0, 2.0);
        vec.emplace_back(31.0, 32.0, 33.0, 3.0);

        vec.emplace_back(37.0, 38.0, 39.0, 1.0);
        vec.emplace_back(40.0, 41.0, 42.0, 2.0);
        vec.emplace_back(43.0, 44.0, 45.0, 3.0);

        std::vector<double> knotsU{0, 0, 0, 0, 1, 1, 1, 1};
        std::vector<double> knotsV{0, 0, 0, 1, 1, 1};

        auto surface = std::make_shared<geom::Geom_BSplineSurface<3, true>>(std::move(vec), std::move(knotsU),
                                                                            std::move(knotsV), 3, 2);
        auto adaptor = Adaptor_OCCBSplineSurface<3, true>(surface.get());

        std::shared_ptr<geom::Geom_BSplineSurface<3, true>> sur = adaptor;
        Handle(::Geom_BSplineSurface) occSurface = adaptor;

        for (int i = 0; i < 10; i++)
        {
            for (int j = 0; j < 10; j++)
            {
                geom::Vec3 p1 = Adaptor_OCCVec<3>(occSurface->Value(i * 0.1, j * 0.1));
                auto p2 = sur->value(i * 0.1, j * 0.1);
                EXPECT_LE((p1 - p2).modulus(), 1e-10);
            }
        }
    }

    // occ 加权曲面转 geom
    {
        TColgp_Array2OfPnt vec(1, 4, 1, 3);
        vec.SetValue(1, 1, gp_Pnt(1.0, 2.0, 3.0));
        vec.SetValue(1, 2, gp_Pnt(4.0, 5.0, 6.0));
        vec.SetValue(1, 3, gp_Pnt(7.0, 8.0, 9.0));

        vec.SetValue(2, 1, gp_Pnt(13.0, 14.0, 15.0));
        vec.SetValue(2, 2, gp_Pnt(16.0, 17.0, 18.0));
        vec.SetValue(2, 3, gp_Pnt(19.0, 20.0, 21.0));

        vec.SetValue(3, 1, gp_Pnt(25.0, 26.0, 27.0));
        vec.SetValue(3, 2, gp_Pnt(28.0, 29.0, 30.0));
        vec.SetValue(3, 3, gp_Pnt(31.0, 32.0, 33.0));

        vec.SetValue(4, 1, gp_Pnt(37.0, 38.0, 39.0));
        vec.SetValue(4, 2, gp_Pnt(40.0, 41.0, 42.0));
        vec.SetValue(4, 3, gp_Pnt(43.0, 44.0, 45.0));

        TColStd_Array2OfReal weights(1, 4, 1, 3);
        weights.SetValue(1, 1, 1.0);
        weights.SetValue(1, 2, 2.0);
        weights.SetValue(1, 3, 3.0);

        weights.SetValue(2, 1, 1.0);
        weights.SetValue(2, 2, 2.0);
        weights.SetValue(2, 3, 3.0);

        weights.SetValue(3, 1, 1.0);
        weights.SetValue(3, 2, 2.0);
        weights.SetValue(3, 3, 3.0);

        weights.SetValue(4, 1, 1.0);
        weights.SetValue(4, 2, 2.0);
        weights.SetValue(4, 3, 3.0);

        std::vector<double> knotsU{0, 0, 0, 0, 1, 1, 1, 1};
        std::vector<double> knotsV{0, 0, 0, 1, 1, 1};
        auto kA = Adaptor_OCCKnot(knotsU);
        auto [KnotsU, MultsU] = kA.occ();
        auto kB = Adaptor_OCCKnot(knotsV);
        auto [KnotsV, MultsV] = kB.occ();

        Handle(::Geom_BSplineSurface) surface =
            new ::Geom_BSplineSurface(vec, weights, KnotsU, KnotsV, MultsU, MultsV, 3, 2);
        auto adaptor = Adaptor_OCCBSplineSurface<3, true>(surface);

        std::shared_ptr<geom::Geom_BSplineSurface<3, true>> sur = adaptor;
        Handle(::Geom_BSplineSurface) occSurface = adaptor;

        for (int i = 0; i < 10; i++)
        {
            for (int j = 0; j < 10; j++)
            {
                geom::Vec3 p1 = Adaptor_OCCVec<3>(occSurface->Value(i * 0.1, j * 0.1));
                auto p2 = sur->value(i * 0.1, j * 0.1);
                EXPECT_LE((p1 - p2).modulus(), 1e-10);
            }
        }
    }
}

TEST(TestAdaptorEigen, Matrix)
{
    {
        Eigen::MatrixXd mat(3, 3);
        mat.setRandom();

        // std::cout << mat << std::endl;

        Adaptor_EigenMatrix adaptor(mat);

        math::MatrixXd mat2 = adaptor;
        Eigen::MatrixXd mat3 = adaptor;

        // std::cout << mat2 << std::endl;
        // std::cout << mat3 << std::endl;
    }

    {
        math::MatrixXd mat(3, 3);
        mat.set_random();

        // std::cout << mat << std::endl;

        Adaptor_EigenMatrix adaptor(mat);

        math::MatrixXd mat2 = adaptor;
        Eigen::MatrixXd mat3 = adaptor;

        // std::cout << mat2 << std::endl;
        // std::cout << mat3 << std::endl;
    }
}